package org.jaaksi.kottlindemo.test

import android.content.Context
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.preferencesDataStore
import androidx.lifecycle.lifecycleScope
import extension.dataStore
import kotlinx.android.synthetic.main.activity_test_cou.*
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import libcore.eventbus.EventBusInitializer.application
import libcore.kotpref.AppSp
import org.jaaksi.kottlindemo.R
import org.jetbrains.anko.doAsync
import org.jetbrains.anko.internals.AnkoInternals.createAnkoContext
import org.jetbrains.anko.toast
import org.jetbrains.anko.uiThread
import timber.log.Timber
import java.lang.IllegalArgumentException
import kotlin.system.measureTimeMillis
import kotlin.time.measureTime

// TestCoroutineActivity
class TestCoroutineActivity : AppCompatActivity() {
    private var num = "111"

    // 在非lifecycle viewmodel等现成的作用域时，可以自己创建一个作用域
    // context指定Dispatchers + SupervisorJob()
    // 协程上下文指定SupervisorJob时，该协程中的异常不会向外传播，因此不会影响其父亲/兄弟协程，也不会被其兄弟协程抛出的异常影响
    private val coroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())

    // 其实这种写法本质等同于调用 MainScope()
    private val coroutineScope2 = CoroutineScope(Dispatchers.Main + SupervisorJob())

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test_cou)

        btn_click.setOnClickListener {
            testDelay()
        }

    }

    fun testDelay(){
        lifecycleScope.launch {
            Timber.e("读取耗时任务完毕")
        }
    }

    fun testLazy(){
       // fixme 包括主动调用该协程的start、join或者await等函数时才会开始调度，如果调度前就被取消，协程将直接进入异常结束状态。
        val job = lifecycleScope.launch(start = CoroutineStart.LAZY) {
            Timber.e("launch CoroutineStart.LAZY")
        }
        runBlocking { delay(1000) }
        Timber.e("start before")
        job.start()
        Timber.e("start before")
    }

    fun test3333(){
        lifecycleScope.launch {
            dataStore.edit {
                it[booleanPreferencesKey("111")] = true
            }
            dataStore.edit {
                it[booleanPreferencesKey("2222")] = true
            }

            dataStore.data.collect {
                it[booleanPreferencesKey("111")]
            }
        }
    }

    fun testFlow2(){
        lifecycleScope.launch {
            flowOf(1).collect {
                delay(1000)
                Timber.e("1111")
            }
            Timber.e("2222")
            Timber.e("3333")
            flowOf(1).collect {
                delay(2000)
                Timber.e("4444")
            }
        }
    }

    fun testFlow() {
        var period = 1000L
        var lastTime = 0L
        lifecycleScope.launch {
            flow {
                repeat(1000) {
                    if (it > 50) {
                        period = 2000
                    }
                    emit(it)
                    delay(100)
                }
            }.filter {
                (System.currentTimeMillis() - lastTime > period).apply {
                    if (this) lastTime = System.currentTimeMillis()
                }
            }
                .collect {
                    Timber.e("$it")
                }
        }
    }

    //  3 4 1 2
    fun testMainScope() {
        val job = lifecycleScope.launch {
            println(">>1 delay")
            // 协程被挂起，主线程继续执行下面的代码
            delay(20)
            println(">>2 coroutine end")
        }
        println(">>3 Thread sleep start")
        Thread.sleep(1000)
        println(">>4 Thread sleep end")
        job.cancel()

    }

    // invokeOnCompletion监听协程执行完毕的回调
    fun test111() {
        val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
            Timber.e(throwable)
        }
        val job = lifecycleScope.launch(exceptionHandler) {
            delay(1000)
            throw IllegalArgumentException("111")
        }
        job.invokeOnCompletion {
            // 如果没有发生异常，it为null
            Timber.e(it) // 如果cancel，这里也会受到回调,cancelException
        }
        // job的几种状态
        job.isActive
        job.isCancelled
        job.isCompleted
        lifecycleScope.launch {
            delay(100)
            job.cancel()
            // 协程的join是挂起，直到协程完成
            job.join()
        }
    }

    private fun testRun() {
        Timber.e("111 ${Thread.currentThread()}")
        runBlocking(Dispatchers.IO) {
            Timber.e("runBlocking(Dispatchers.IO) in ${Thread.currentThread()}")
        }
        Timber.e("222 ${Thread.currentThread()}")
    }

    private fun testContext() {
        //fixme CoroutineContext是一组用于定义协程行为的元素。它由如下几项构成：
//        1.Job:控制协程的生命周期。
//        2.CoroutineDispatcher:向合适的线程分发任务。
//        3.CoroutineName:协程的名称，调试的时候很有用。
//        4.CoroutineExceptionHandle:处理未被捕捉的异常。
    }

    private fun testUnconfined() {
        // Dispatchers.Unconfined不指定线程
        // Dispatchers.Unconfined 协程调度器在调用它的线程启动了一个协程，但它仅仅只是运行到第一个挂起点。
        // 挂起后，它恢复线程中的协程，而这完全由被调用的挂起函数来决定。
        // 非受限的调度器非常适用于执行不消耗 CPU 时间的任务，以及不更新局限于特定线程的任何共享数据（如UI）的协程。
        lifecycleScope.launch(Dispatchers.IO) {
            Timber.e("lifecycleScope launch IO = ${Thread.currentThread().name}")
            // 子协程切换线程代码会运行在原来的线程上，协程在相应的挂起函数使用的任何线程中继续。
            launch(Dispatchers.Unconfined) {
                Timber.e("IO launch Unconfined = ${Thread.currentThread().name}")
                delay(1000)
                Timber.e("after delay Unconfined = ${Thread.currentThread().name}")
            }
        }


    }



    private fun testDispatcher() {
        // fixme 1.在非协程作用域中直接创建一个CoroutineScope，默认是Dispatchers.Default。
        // fixme Dispatchers.Default和GlobalScope.launch的默认调度器一样，共享的后台线程池
        CoroutineScope(Job()).launch {
            // DefaultDispatcher-worker-2 @coroutine#11
            Timber.e("no scope CoroutineScope.launch = " + Thread.currentThread().name)
        }

        // DefaultDispatcher-worker-2 @coroutine#2
        GlobalScope.launch {
            Timber.e("GlobalScope.launch = " + Thread.currentThread().name)
        }

        // IO调度器，非主线程，执行的线程是IO线程。适合执行IO相关操作，比如：网络处理，数据库操作，文件读写等。
        // DefaultDispatcher-worker-3 @coroutine#3
        GlobalScope.launch(Dispatchers.IO) {
            Timber.e("GlobalScope.launch(Dispatchers.IO) = " + Thread.currentThread().name)
        }

        CoroutineScope(newSingleThreadContext("单线程线程池")).launch {
            Timber.e("newSingleThreadContext = " + Thread.currentThread().name)
        }

        CoroutineScope(newFixedThreadPoolContext(3, "3个线程的线程池")).launch {
            Timber.e("newFixedThreadPoolContext3 = " + Thread.currentThread().name)
        }


        GlobalScope.launch(Dispatchers.Main) {
            Timber.e("GlobalScope.launch(Dispatchers.Main) = " + Thread.currentThread().name)
            // fixme 2.在协程作用域中，不传参数，它会使用 父协程的上下文（以及调度器）
            launch {
                Timber.e("with parent scope launch = " + Thread.currentThread().name)
            }

            // fixme 3.Dispatchers.Default和GlobalScope.launch的默认调度器一样，共享的后台线程池
            // 默认调度器，非主线程。CPU密集型任务调度器，适合处理后台计算。通常处理一些单纯的计算任务，或者执行时间较短任务比如：Json的解析，数据计算等。
            // DefaultDispatcher-worker-2 @coroutine#6
            launch(Dispatchers.Default) {
                Timber.e("with parent scope launch(Dispatchers.Default) = " + Thread.currentThread().name)
            }

            //fixme newSingleThreadContext 为协程的运行启动了一个线程。
            // 一个专用的线程是一种非常昂贵的资源。
            // 在真实的应用程序中两者都必须被释放，当不再需要的时候，使用 close 函数，或存储在一个顶层变量中使它在整个应用程序中被重用。
//            val context = newSingleThreadContext("")
//            launch(context) {
//                delay(1000)
//                context.close()
//            }

        }
    }


    fun test() {
        application.applicationContext.doAsync {
            println(">> doAsync ${Thread.currentThread()}")
            uiThread {
                println(">> uiThread ${Thread.currentThread()}")
            }
        }
    }

    /**
     * deferred1.await
     * deferred1 async
     * deferred2 async
     * deferred2 async end
     * deferred1 async end
     * deferred2.await
     * deferred2.await end
     *
     */
    private fun testAsync() {
        // async异步（用来作并发），也可以指名start为
        lifecycleScope.launch(CoroutineName("1")) {
            // async是开了个新的协程
            val deferred1 = async(CoroutineName("2")) {
                Timber.e("deferred1 async")
                delay(2000)
                Timber.e("deferred1 async end")
            }
            val deferred2 = async(CoroutineName("3")) {
                Timber.e("deferred2 async")
                delay(1000)
                Timber.e("deferred2 async end")
            }
            Timber.e("deferred1.await")
            deferred1.await() // 挂起协程1，需要等deferred1的协程执行完毕
            Timber.e("deferred2.await")
            deferred2.await()
            Timber.e("deferred2.await end")
        }
    }

    private fun testThreadPoll() {
//        lifecycleScope.launch(newSingleThreadContext("")){}
        lifecycleScope.launch(newFixedThreadPoolContext(3, "")) {}
    }

    private fun testLazyAsync() {
        lifecycleScope.launch {
            // fixme async 可以通过将 start 参数设置为 CoroutineStart.LAZY 而变为惰性的。
            // 在这个模式下，只有结果通过 await 获取的时候协程才会启动，或者在 Job 的 start 函数调用的时候
            val time = measureTimeMillis {
                val deferred1 = async(start = CoroutineStart.LAZY) {
                    Timber.e("deferred1 async")
                    delay(2000)
                    Timber.e("deferred1 async end")
                }
                val deferred2 = async(start = CoroutineStart.LAZY) {
                    Timber.e("deferred2 async")
                    delay(1000)
                    Timber.e("deferred2 async end")
                }
                Timber.e("deferred1.await")
                deferred1.await() // 挂起协程1，需要等deferred1的协程执行完毕
                Timber.e("deferred2.await")
                deferred2.await()
                Timber.e("deferred2.await end")
            }
            // 3025,由于这里使用的是Lazy，deferred1.await()挂起协程，deferred2的async没有执行。
            // deferred1执行完毕后，恢复协程，deferred2.await()才开始执行，所以执行时间>3s
            Timber.e("time = $time")
        }
    }

    suspend fun test1() = coroutineScope {
        // 作用域可以嵌套作用域
        launch {
            delay(1000)
            Timber.e("test1 launch delay 1000")
        }
        delay(1000)
        Timber.e("test1 delay 1000")
    }

    fun test2() {
        coroutineScope.launch { }

        // 会cancel所有coroutineScope 启动的协程
        coroutineScope.cancel()
    }

    suspend fun test3() {
        val startTime = System.currentTimeMillis()
        val job = coroutineScope.launch(Dispatchers.Default) {
            var nextPrintTime = startTime
            var i = 0
            // 取消协程并不能停止正在执行的线程，通过判断CoroutineScope.isActive判断协程是否取消协同处理
            while (i < 5 && isActive) {
                //ensureActive()的实现是 if (!isActive) throw getCancellationException()，如果!isActive会抛异常
                ensureActive()
                if (System.currentTimeMillis() >= nextPrintTime) {
                    println("Hello ${i++}")
                    nextPrintTime += 500L
                }
            }
            println("Clean up!")
        }
        delay(1000L)
        println("Cancel!")
        job.cancel()
        println("Done!")
    }

    override fun onDestroy() {
        super.onDestroy()
        // 取消仍未结束的协程，触发后作用域对象再启动协程的代码不再执行
        coroutineScope.cancel()
        // 取消仍未结束的协程，触发后作用域对象再启动协程的代码仍会执行
        coroutineScope.coroutineContext.cancelChildren()
    }

}